home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / Book Chapters / 00 - Game Programming Primer / HelloWorld2.c < prev    next >
Text File  |  1995-06-26  |  14KB  |  326 lines

  1. //==============================================================================================\\
  2. //        -----------------------------------------------------------------------------------        \\
  3. //        HelloWorld2.c version 1.0.0    copyright © 1993…1995 Jamie McCornack, john calhoun            \\
  4. //        -----------------------------------------------------------------------------------        \\
  5. //         Demo program for Macintosh GameWriter 1.0.0, a training program…                        \\
  6. //        …for beginning Mac game programmers. MGW1 includes MGWExterns1.h, MGWUtilities1.c,…        \\
  7. //        …MGWSound1.c, MGWGraphics1.c, MGWGraphicsBWLite1.c, HelloWorld.rsrc and an assortment…    \\
  8. //        …of demo programs; projects HelloWorld1.π etc. and source code files HelloWorld1.c etc.    \\
  9. //         A tutorial is available in Tricks of the Mac Game Programming Gurus, published…        \\
  10. //        …by Hayden Books, August 1995.                                                            \\
  11. //                                                                                                \\
  12. //        This code is offered by the copyright holders for no fee and for whatever use…            \\
  13. //        …you care to make of it, but we do hope you remember where it came from.                \\
  14. //                                                                                                \\
  15. //        Please send bug reports to MacGameDev at America OnLine.    macgamedev@aol.com            \\
  16. //        Suggestions and observations are also appreciated.                                        \\
  17. //        Updates and upgrades will be available now and then from the above e-mail address.        \\
  18. //==============================================================================================\\
  19.  
  20. // This program opens a window, displays an 8-bit color background, and at first…
  21. // …mouseclick, runs a clam across the screen. At second mouseclick, the clam stops,…
  22. // …talks, and flaps its/his/her face for 40 frames. Then the program quits.
  23.  
  24.  
  25. #include "MGWExterns1.h"
  26.  
  27. #define     kPutInFront    (WindowPtr)-1L
  28. #define     kWaitTicks     4L    // Sets the delay in Ticks between frames. Try 3. Try 2. Try 0.
  29. #define     kStepLength    14    // Sets the distance in pixels between sprite moves.
  30. #define  kFrontFace        0
  31. #define  kBlinkFace     1
  32. #define  kEehFace        2
  33. #define  kOohFace        3
  34. #define  kStepRightFace    4
  35. #define  kWalkRightFace    5
  36. #define  kRunRightFace    6
  37. #define  kMaxFaces        7
  38.                 // The resource constants--with 'r' prefix like Apple wants them.}
  39. #define  rFacesID        136        // The 'PICT' ID# where the views of the clam are located.}
  40. #define  rMasksID        130        // The 'PICT' ID# where the clam masks are located.}
  41. #define  rBackgroundID    134    // The 'PICT' ID# where the background picture is located.}
  42. #define  rMainWindowID    128    // The 'WIND' resource ID# for the main window.}
  43.  
  44. #define  rHelloSndID    3000
  45. #define  rFootstepSndID    3001
  46. #define  rImpactSndID    3002
  47. #define  rDizzySndID    3003
  48.  
  49. #define  kColorBitsNeeded    8
  50.     
  51. typedef struct
  52. {
  53.     Rect    face;
  54.     Rect    mask;
  55. } tSpriteType;
  56.  
  57.  
  58. Rect    bigPictureRect, facesRect, masksRect, clamIsAtRect, clamWasAtRect, clamComboRect;
  59. CGrafPtr    workCPort, facesCPort, backgroundCPort;
  60. GrafPtr mainWindow, masksPort;
  61. Boolean    itWorked;
  62. long    targetTick;
  63. short        thisSprite, thisFaceCounter;
  64.  
  65. tSpriteType    sprite[kMaxFaces];
  66.  
  67. extern    Boolean        gUserWantsSound;
  68.     
  69.     
  70. //==============================================================  Prototypes
  71.  
  72. void InitAll(void);
  73. void OpenMainWindow (void);
  74. void SetTheRects(void);
  75. void SetTheCPorts(void);
  76. void ShowClam (void);
  77. void DoDelay (void);
  78. void RunRight (void);
  79. void LipSynch (void);
  80.  
  81. //==============================================================  Functions
  82.  
  83. //--------------------------------------------------------------  InitAll
  84.  
  85. void InitAll(void)
  86. {
  87.     InitToolbox();
  88.     if (WhatsOurDepth() != kColorBitsNeeded)    // Compare color depth with what…
  89.         RedAlert(kErrNot8BitColor);                // …we want. If not equal, exit.
  90.     gUserWantsSound = TRUE;
  91.     InitializeForSound();
  92.     SetTheRects();        // Since some of these Rects define fields in CGrafPorts,…
  93.     SetTheCPorts();        // …set the rects before setting the ports.
  94.     thisSprite = kFrontFace;
  95.     thisFaceCounter = 0;
  96.     targetTick = TickCount() + kWaitTicks;
  97.     HideCursor();        // This demo doesn't use mouse input, so why look at it?
  98. }
  99.  
  100. //--------------------------------------------------------------  OpenMainWindow
  101.  
  102. void OpenMainWindow (void)
  103. {
  104.     mainWindow = GetNewCWindow(128, 0L, kPutInFront);    // Load window from resource.
  105.     ShowWindow((GrafPtr)mainWindow);                    // Now display it.
  106.     SetPort((GrafPtr)mainWindow);                        // Make its port current.
  107.     ClipRect(&bigPictureRect);                            // Set its clip region.
  108.     CopyRgn(mainWindow->clipRgn, mainWindow->visRgn);    // Set its visRgn.
  109.     ForeColor(blackColor);                                // Set its pen color to black.
  110.     BackColor(whiteColor);                                // Set background color white.
  111. }
  112.  
  113. //--------------------------------------------------------------  SetTheRects
  114.  
  115. void SetTheRects(void)    // The most tedious part of programming this type of game.
  116. {
  117.     SetRect(&facesRect, 0, 0, 448, 64);        // Size and shape of BitMap for the sprite faces.
  118.     SetRect(&masksRect, 0, 0, 448, 32);        // Size and shape of BitMap for the sprite masks.
  119.     SetRect(&bigPictureRect, 0, 0, 512, 322);    // The shape of the picture we'll put in the main window, workCPort and backgroundCPort.}
  120.     SetRect(&clamIsAtRect, 200, 244, 232, 276);    // The shape (32 x 32) of the images of Clem, and the position of the first image.}
  121.     clamWasAtRect = clamIsAtRect;                // Initializing clamIsAtRect...it has to start somewhere, and this is handy.}
  122.     clamComboRect = clamIsAtRect;
  123.         // And now, the tedium. In this sample, all we're doing is showing the clam running across the screen to the right.}
  124.         // However, if you use ResEdit and look at 'PICT' 129 in Sample.rsrc, you'll find 28 different views of the clam.}
  125.         // If we wanted the clam to run left too, and walk slowly, and face the user, and blink its eyes, we'd be calling…}
  126.         // …SetRect 56 times--one face and one mask per sprite. And if we had jumping clams and rear views of clams…}
  127.         // …and starfish and clamdiggers and other hazards of the clam environment, we might have hundreds of rects to set.}
  128.     SetRect(&sprite[kFrontFace].face, 320, 32, 352, 64);    // The shape and position of sprite[kFrontFace].face on facesCPort.portPixMap.
  129.     SetRect(&sprite[kFrontFace].mask, 320, 0, 352, 32);    // The shape and position of sprite[kFrontFace].mask on masksPort.portPixMap.
  130.     SetRect(&sprite[kBlinkFace].face, 320, 0, 352, 32);    // Note that some faces (e.g. eyes open or closed) use the same mask,…
  131.     SetRect(&sprite[kBlinkFace].mask, 320, 0, 352, 32);    // …since they have the same silhouette.}
  132.     SetRect(&sprite[kEehFace].face, 352, 0, 384, 32);    // I could write more comments here, but setting these rects…
  133.     SetRect(&sprite[kEehFace].mask, 352, 0, 384, 32);    // …is already tedious enough without a bunch of busy-work.
  134.     SetRect(&sprite[kOohFace].face, 352, 32, 384, 64);
  135.     SetRect(&sprite[kOohFace].mask, 352, 0, 384, 32);    
  136.     SetRect(&sprite[kStepRightFace].face, 192, 0, 224, 32);    
  137.     SetRect(&sprite[kStepRightFace].mask, 192, 0, 224, 32);    
  138.     SetRect(&sprite[kWalkRightFace].face, 224, 0, 256, 32);    
  139.     SetRect(&sprite[kWalkRightFace].mask, 224, 0, 256, 32);    
  140.     SetRect(&sprite[kRunRightFace].face, 160, 0, 192, 32);    // BTW, there are plenty more clam faces and masks in the 'PICT's,…
  141.     SetRect(&sprite[kRunRightFace].mask, 160, 0, 192, 32);    // …if you feel you need rect setting practice.  :-)
  142. }
  143.  
  144. //--------------------------------------------------------------  SetTheCPorts
  145.  
  146. void SetTheCPorts(void)    // Create the CGrafPorts and load their .portPixMap fields.
  147. {
  148.             // Create BitMap for sprite masks. NOTE THIS IS A BITMAP!
  149.     CreateOffScreenBitMap (&masksRect, &masksPort);
  150.     LoadGraphic (rMasksID);        // …load 'PICT' resource for the clam masks.
  151.     
  152.             // Create PixMap for sprite faces.
  153.     CreateOffScreenPixMap (&facesRect, &facesCPort);
  154.     LoadGraphic (rFacesID);        // …load 'PICT' resource for the clam faces.
  155.  
  156.             // Create PixMap for the background.
  157.     CreateOffScreenPixMap (&bigPictureRect, &backgroundCPort);
  158.     LoadGraphic(rBackgroundID);    // …load 'PICT' resource for the background picture.
  159.     
  160.             // Create PixMap for offscreen graphics work.
  161.     CreateOffScreenPixMap (&bigPictureRect, &workCPort);
  162.  
  163.     OpenMainWindow();
  164.  
  165.         //{This fills the main window with the background picture, so the user can see it.
  166.     CopyBits(&((GrafPtr)backgroundCPort)->portBits,
  167.         &((GrafPtr)mainWindow)->portBits, 
  168.         &bigPictureRect, &bigPictureRect, srcCopy, mainWindow->visRgn);
  169.  
  170. // This fills the workCPort.portPixMap with the background picture, so updates can be done quickly.
  171.     CopyBits(&((GrafPtr)backgroundCPort)->portBits,
  172.         &((GrafPtr)workCPort)->portBits, 
  173.         &bigPictureRect, &bigPictureRect, srcCopy, mainWindow->visRgn);
  174. }
  175.  
  176. //--------------------------------------------------------------  ShowClam 
  177.  
  178. void ShowClam (void)    // Do the animation and make it appear on the screen.
  179. {
  180.     CopyMask(&((GrafPtr)facesCPort)->portBits, 
  181.         &((GrafPtr)masksPort)->portBits, 
  182.         &((GrafPtr)workCPort)->portBits, 
  183.         &sprite[thisSprite].face, 
  184.         &sprite[thisSprite].mask, 
  185.         &clamIsAtRect);
  186. // Now there is an image of a clam in the new position in workMap.  If we had done this work in…
  187. // mainWindow, we would have seen considerable flickering.  Instead, we did it offscreen, and left the…
  188. // previous image of the clam visible on the screen while we worked.
  189.  
  190.     UnionRect(&clamWasAtRect, &clamIsAtRect, &clamComboRect);
  191. // Find the smallest rectangle which will cover the old position of the clam and the new.
  192.  
  193.     CopyBits(&((GrafPtr)workCPort)->portBits, 
  194.         &(((GrafPtr)mainWindow)->portBits), 
  195.         &clamComboRect, &clamComboRect, srcCopy, mainWindow->visRgn);
  196. // Copy the contents of comboRect from workCPort->portPixMap to the main window. In one swell foop, the old clam…}
  197. //…will be erased, and the new clam overlayed onto the background picture. Wallah! Flicker-free animation!}
  198.  
  199.     CopyBits(&((GrafPtr)backgroundCPort)->portBits, 
  200.         &(((GrafPtr)workCPort)->portBits), 
  201.         &clamIsAtRect, &clamIsAtRect, srcCopy, mainWindow->visRgn);
  202. // Restore the workCPort by covering up our clam with the background it obscures.
  203. // This way, workCPort->portPixMap is identical to backgroundCPort->portPixMap,…
  204. // without having to copy the entire PixMap.
  205. }
  206.  
  207. //--------------------------------------------------------------  DoDelay
  208.  
  209. // This is the companion function to the above function (LogNextTick()).
  210. // We do nothing but loop until TickCount() catches up with (or passes) our…
  211. // global variable tickNext.
  212.  
  213. void DoDelay (void)
  214. {
  215.     do
  216.     {
  217.     }
  218.     while (TickCount() < targetTick);            // Loop until TickCount() catches up.
  219.     targetTick = TickCount() + kWaitTicks;
  220. }
  221. //--------------------------------------------------------------  RunRight
  222.  
  223. void RunRight (void)    //Gives a sequence of views of the clam running to the right.
  224. {
  225.     switch    (thisSprite)                    //If the current view of the clam is…
  226.     {    case    (kStepRightFace):             // …kStepRightFace, then set thisSprite to…
  227.         {    thisSprite = kWalkRightFace;    // …kWalkRightFace, and if it is currently…
  228.             break;    }
  229.         case    (kWalkRightFace):             // …kWalkFace, then set it to…
  230.         {    thisSprite = kRunRightFace;        // …kRunRightFace.
  231.             PlayASound(rFootstepSndID, kHighestSoundPriority);    // Note sound priority.
  232.             break;    }
  233.     // And if it was neither kStepRightFace nor kWalkRightFace, then thisSprite was either…
  234.         default                    :             // …kRunRightFace, or what it was when RunRight()…
  235.             thisSprite = kStepRightFace;    // …was called, so we set it to kStepRightFace
  236.     }
  237.     clamWasAtRect = clamIsAtRect;            // Store the clam's current position as its last position,…
  238.                                             // …we'll be erasing it next time through the loop.
  239.     OffsetRect(&clamIsAtRect, kStepLength, 0);    // Set the clam's next position--it'll be…
  240.                                             // …kStepLength pixels to the right of its last position.
  241.     if (clamIsAtRect.left > 512)                // If the clam has wandered out of sight,…
  242.     {                                        // …set the right border of clamIsAtRect…
  243.         clamIsAtRect.right = 0;                // …to the left edge of the screen…
  244.         clamIsAtRect.left = -32;            // …and move the left border of clamIsAtRect…
  245.     }                                        // …as needed to maintain its 32 x 32 shape & size.
  246.   ShowClam();                        // The actual animation routine!
  247.   DoDelay();    // Do nothing for a while. In a real game, you'll want to use time more wisely.
  248. }
  249.  
  250. //--------------------------------------------------------------  LipSynch
  251.  
  252. // This routine has the clam stop moving, face the screen, and move its face.
  253.  
  254. void LipSynch (void)
  255. {
  256.     while (thisFaceCounter < 40)
  257.     {
  258.         thisFaceCounter = thisFaceCounter + 1;
  259.          switch (thisFaceCounter)
  260.          {    case    (1): 
  261.             {    thisSprite = kFrontFace;
  262.                 break;    }
  263.             case    (2): 
  264.             {    thisSprite = kEehFace;
  265.                 break;    }
  266.             case    (4): 
  267.             {    thisSprite = kFrontFace;
  268.                 break;    }
  269.             case    (5): 
  270.             {    thisSprite = kOohFace;
  271.                 break;    }
  272.             case    (9): 
  273.             {    thisSprite = kEehFace;
  274.                 break;    }
  275.             case    (11): 
  276.             {    thisSprite = kOohFace;
  277.                 break;    }
  278.             case    (13): 
  279.             {    thisSprite = kFrontFace;
  280.                 break;    }
  281.             case    (16): 
  282.             {    thisSprite = kBlinkFace;
  283.                 break;    }
  284.             case    (18): 
  285.             {    thisSprite = kFrontFace;
  286.                 break;    }
  287.             case    (35): 
  288.             {    thisSprite = kBlinkFace;
  289.                 break;    }
  290.             case    (38): 
  291.             {    thisSprite = kFrontFace;
  292.                 break;    }
  293.         }
  294.         ShowClam();
  295.         DoDelay();        // Do nothing for a while, so the lips don't flap too fast.
  296.     }
  297. }
  298.  
  299. //--------------------------------------------------------------  main
  300. //----------------------------------------------------------------------
  301.  
  302. void main(void)
  303. {
  304.     InitAll();
  305.     while (!Button())    // Before the user presses the mouse button, nothing happens.
  306.         {
  307.         }
  308.     while (Button())    // When the user presses the mouse button, nothing happens.
  309.         {
  310.         }
  311.     while (!Button())    // When the mouse button is released, continue to…
  312.         {
  313.         RunRight();        // …show the clam running right (duh),…
  314.         }
  315.     while (Button())    // …until the button is pushed.
  316.         {                // Do nothing until the button is released.
  317.         }
  318.     PlayASound(rHelloSndID, kMediumSoundPriority);
  319.     LipSynch();
  320.     CloseDownSound();
  321. }                        // And we're done.
  322.  
  323. //------------------------------------------------------------------------------------------\\
  324. //                                    End HelloWorld1.c                                        \\
  325. //------------------------------------------------------------------------------------------\\
  326.